<?php
/**
 * @package pmapi
 * @copyright Copyright (c)2014 Enrico Fagnoni
 * @license GNU General Public License version 3, or later
 *
 * @since 1.0.0
 */
 
defined('_JEXEC') or die;


/**
 * this joomla view realizes an abstract http controller for the display task. 
 * It also implements content negotiation.
 * 
 * child of this class must implement this methods or you get a 405 http error:
 *  GET_RequestProcessor : default implementation provided
 *  HEAD_RequestProcessor: default implementation provided
 *  POST_RequestProcessor
 *  PUT_RequestProcessor
 *  DELETE_RequestProcessor
 *  PATCH_RequestProcessor
 *  TRACE_RequestProcessor
 *  CONNECT_RequestProcessor
 *  OPTIONS_RequestProcessor : default implementation provided
 * 
 */
abstract class LinkedDataView extends JViewLegacy
{
    protected $httpMethod = 'GET';

    
    public function __construct($config = array())
    {
        parent::__construct($config);
        $this->httpMethod = strtoupper(JFactory::getApplication()->input->server->get('REQUEST_METHOD','GET'));
    }

   
    abstract protected function _computeETag();

    
    public function getETag()
    {
        static $_etag = null;
        if (is_null($_etag)) $_etag =$this->_computeETag();
        
        return $_etag;
    }


    private function _getBestSupportedMimeType($accept, array $mimeTypes) {
        // Values will be stored in this array
        $AcceptTypes = Array ();

        // Accept header is case insensitive, and whitespace isn’t important
        $accept = strtolower($accept);
        // divide it into parts in the place of a ","
        $accept = explode(',', $accept);
        foreach ($accept as $a) {
            // the default quality is 1.
            $q = 1;
            // check if there is a different quality
            if (strpos($a, ';q=')) {
                // divide "mime/type;q=X" into two parts: "mime/type" i "X"
                list($a, $q) = explode(';q=', $a);
            }
            // mime-type $a is accepted with the quality $q
            // WARNING: $q == 0 means, that mime-type isn’t supported!
            $AcceptTypes[$a] = $q;
        }
        arsort($AcceptTypes);
    
        $mimeTypes = array_map('strtolower', (array)$mimeTypes);
    
        // let’s check our supported types:
        foreach ($AcceptTypes as $mime => $q) {
           if ($q && in_array($mime, $mimeTypes)) return $mime;
        }
        // no mime-type found
        return 'text/turtle';
    }

    /**
     * Detect format using same naming convention of EasyRdf and setuo http header according to it.
     */
    private function _negotiateContent($tpl)
    {
        $jinput = JFactory::getApplication()->input;
        if (is_null($tpl)) $tpl = $jinput->get('layout',null); // antipattern management
        
        if (is_null($tpl)) {
            // content negotiation management
            $accept = $jinput->server->get('HTTP_ACCEPT','text/turtle','raw');
            $format = $this->_getBestSupportedMimeType($accept,array(
                'text/turtle',
                'text/ntriples',
                'application/rdf+xml',
                'text/n3',
                'application/json',
                'application/rdf+json',
            ));
            switch ($format) {
                case 'text/ntriples':
                    $tpl = 'ntriples';
                    break;
                case 'application/rdf+xml':
                    $tpl = 'rdfxml';
                    break;
                case 'text/n3':
                    $tpl = 'n3';
                    break;
                case 'application/json':
                case 'application/rdf+json':
                    $format='application/rdf+json';
                    $tpl = 'json';
                    break;    
                default:
                    $format = 'text/turtle';
                    $tpl = 'turtle';                
                    break;
            }
            JFactory::getDocument()->setMimeEncoding($format);
        }
        return $tpl;     
    }


    private function _writeRepresentation($tpl)
    {
        $tpl = $this->_negotiateContent($tpl);

        if ($tpl == 'turtle'){
            // turtle is already done by template: using the joomla default display method
            parent::display($tpl);        
        } elseif (in_array($tpl,array('ntriples','rdfxml','n3','json'))) {
            //load EasyRdf library
            require_once JPATH_COMPONENT.DS.'libraries'.DS.'EasyRdf.php';

            // load graph from turtle
            $data =$this->loadTemplate('turtle');
            $graph= new EasyRdf_Graph($this->getURI(),$data,'turtle');
            
            //serialize graph according with requested template
            echo $graph->serialise($tpl);
        } else {
            throw new Exception("Not Acceptable", 406);
        }
    }


    protected function GET_RequestProcessor($tpl = null)
    {
        // caching? why not?
        JResponse::allowCache(true);
            
        // set canonical link for seo
        ApiHelper::setHttpLink( $this->getURI(), 'canonical');
        
        // advertise LDP capability
        ApiHelper::setHttpLink( UriHelper::getNamespace('ldp') . ApiHelper::getLDPType(), 'type');
        
        // set ETag
        JResponse::setHeader('ETag','W/"'.$this->getETag().'"');
        
        return $tpl;
    } 


    protected function HEAD_RequestProcessor($tpl = null)
    {
        $this->GET_RequestProcessor();
        return '#';
    } 


    public function OPTIONS_RequestProcessor($tpl = null) 
    {
        $supportedOptions[]='OPTIONS';
        if( method_exists($this, 'GET_RequestProcessor')) { $supportedOptions[]='GET'; $supportedOptions[]='HEAD' ;}
        if( method_exists($this, 'POST_RequestProcessor')) $supportedOptions[]='POST';
        if( method_exists($this, 'PUT_RequestProcessor')) $supportedOptions[]='PUT';
        if( method_exists($this, 'DELETE_RequestProcessor')) $supportedOptions[]='DELETE';
        if( method_exists($this, 'PATCH_RequestProcessor')) $supportedOptions[]='PATCH';
        if( method_exists($this, 'TRACE_RequestProcessor')) $supportedOptions[]='TRACE';
        if( method_exists($this, 'CONNECT_RequestProcessor')) $supportedOptions[]='CONNECT';
        
        header ( 'Allow: '. implode(',', $supportedOptions));

        return '#';   
    }
    
            
    public function display($tpl = null) 
    {
        $processor = $this->httpMethod.'_RequestProcessor';
        if (method_exists($this, $processor)){
            $tpl = $this->$processor($tpl);            
        } else {
            throw new Exception("Method Not Allowed", 405);
        }

        // if tpl == # skip response body renderer
        if ($tpl != '#') {
            $this->_writeRepresentation($tpl);
        }
    }

        
    public function getId($default=null)
    {
         return JFactory::getApplication()->input->get('id',$default);
    } 
    
    
    public function getURI()
    {
         return UriHelper::mkDataURL($this->getName(),$this->getId());
    } 

           
    public function getHomepage()
    {
         return UriHelper::mkHtmlURL($this->getName(),$this->getId());
    }   
        
             
    public function getTurtlePrefixes()
    {        
        // write prefixes in turtle syntax
        $prefixBlock = ''; // do not use absolute uri if not necessary '@base <'.$this->getCanonical()."> .\n";
        foreach ( UriHelper::getLanguageProfile() as $prefix=>$long){
            $prefixBlock .= "@prefix $prefix: <$long> .\n";
        }
        
        return $prefixBlock;
    } 

        
             
    public function getDefaultMetadata()
    {
        $userURI = UriHelper::getCurrenUserURI();
        $etag = $this->getETag();
        $agent = ApiHelper::getAgentId();
        $now= ApiHelper::datetime();
           
        return 
"
<>  a ldp:Resource ;
    dcterms:identifier \"$etag\" ;
    prov:generatedAtTime \"$now\"^^xsd:dateTime ;
    prov:wasGeneratedBy [
        a prov:Activity , o:LinkedDataPublishing ;
        prov:wasAssociatedWith [ 
                a prov:SoftwareAgent ;
                dcterms:identifier \"$agent\" ;
                prov:actedOnBehalfOf <$userURI> ;
        ] ;
    ]
.
";
    }


    public function getDepictionMetadata(VmMediaHandler $image)
    {
        $rdf  = " foaf:depiction <$image->file_url> . \n" ;
        $rdf .= "<$image->file_url>\n";
        $rdf .= "\tdcterms:format \"$image->file_mimetype\" ;\n";   
        if($image->file_url_thumb) $rdf .= "\tfoaf:thumbnail <$image->file_url_thumb> ; \n";
        if($image->file_title) $rdf .= "\tdcterms:title \"$image->file_title\" ; \n" ;
        if($image->file_description) $rdf .= "\tdcterms:description \"$image->file_description\" ;\n" ;
        $rdf .= "\t\n";
           
        return $rdf;
    }
    
}